package com.cashmama.market.api.application.controller.authentication;

import com.cashmama.market.api.application.controller.authentication.personalInfo.InputContent;
import com.cashmama.market.api.application.controller.authentication.vos.AuthenticationContentVo;
import com.cashmama.market.api.application.controller.authentication.vos.InputParams;
import com.cashmama.market.api.application.controller.authentication.vos.ParamOptions;
import com.cashmama.market.api.infras.enums.AuthOptionsEnums;
import com.cashmama.market.api.infras.enums.ProfileInputBaseEnum;
import com.cashmama.market.api.infras.exception.ApplicationException;
import com.fqgj.common.utils.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: yujianfu (mr.vencnet@gmail.com)
 * Date: 2019-12-20
 * Time: 16:30
 */
public abstract class AuthenticationBaseHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationBaseHandler.class);

    public abstract Object content();

    public abstract Object save(Map<String,String> inputParams);

    public static AuthenticationContentVo explain(Object o) {
        List<InputParams> inputParams = new ArrayList<>();
        Field[] fields = o.getClass().getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            InputContent inputContent = fields[i].getAnnotation(InputContent.class);
            if (inputContent == null) {
                continue;
            }

            InputParams inputParam = new InputParams()
                    .setParamName(inputContent.paramName())
                    .setParam(inputContent.param())
                    .setInputDesc(inputContent.inputDesc())
                    .setInputValue(inputContent.inputValue())

                    .setBurialPointName(inputContent.burialPointName())
                    .setReadonly(inputContent.readonly())
                    .setRequired(inputContent.required())
                    .setShow(inputContent.show())

                    .setParamType(inputContent.paramType().getType());

            List<ParamOptions> options = new ArrayList<>();
            if (!AuthOptionsEnums.NO.equals(inputContent.operationEnum())) {
                ProfileInputBaseEnum[] profileInputBaseEnum = inputContent.operationEnum().getProfileInputBaseEnum();

                for (int j = 0, size = profileInputBaseEnum.length; j < size; j++) {
                    options.add(new ParamOptions(profileInputBaseEnum[j].getType(), profileInputBaseEnum[j].getDesc()));
                }
            }

            if (CollectionUtils.isNotEmpty(options)) {
                inputParam.setParamOptions(options);
            }


            inputParams.add(inputParam);
        }

        AuthenticationContentVo authenticationContentVo = new AuthenticationContentVo()
                .setInputParams(inputParams);

        return authenticationContentVo;
    }

    public static Object converseType(Object param, Class<?> paramClass) {
        if ("java.util.List".equals(paramClass.getName())) {
            return Arrays.asList(param);
        }
        //java.util.List  java.util.Set
        // 如果是自定义类型 通过返回值类型 实例化此类 给实例赋值 然后将实例set给引用的对象
        if (!isJavaClass(param.getClass())) {
            System.out.println(param.getClass().getSimpleName() + "---------ceshi--------------");
            return param;
        }
        // 基本数据类型
        String paramString = (String) param;
        if (String.class.equals(paramClass)) {
            return paramString;
        }
        if ((Boolean.TYPE.equals(paramClass)) || (Boolean.class.equals(paramClass))) {
            return Boolean.valueOf(paramString);
        }
        if ((Byte.TYPE.equals(paramClass)) || (Byte.class.equals(paramClass))) {
            return Byte.valueOf(Byte.parseByte(paramString));
        }
        if ((Short.TYPE.equals(paramClass)) || (Short.class.equals(paramClass))) {
            return Short.valueOf(paramString);
        }
        if ((Integer.TYPE.equals(paramClass)) || (Integer.class.equals(paramClass))) {
            return Integer.valueOf(Integer.parseInt(paramString));
        }
        if ((Long.TYPE.equals(paramClass)) || (Long.class.equals(paramClass))) {
            return Long.valueOf(Long.parseLong(paramString));
        }
        if ((Float.TYPE.equals(paramClass)) || (Float.class.equals(paramClass))) {
            return Float.valueOf(Float.parseFloat(paramString));
        }
        if ((Double.TYPE.equals(paramClass)) || (Double.class.equals(paramClass))
                || (Number.class.equals(paramClass))) {
            return Double.valueOf(Double.parseDouble(paramString));
        }
        return paramString;
    }

    public static Object getObject(Object obj, Map<String, String> inputParams) {
        for (String fieldName : inputParams.keySet()){
            try {
                String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                String setMethodName = "set" + methodName;
                Method[] declaredMethods = obj.getClass().getDeclaredMethods();

                InputParams params = new InputParams().setInputValue(inputParams.get(fieldName));
                for (Method m : declaredMethods) {
                    if (m.getName().equals(setMethodName)) {
                        m.setAccessible(true);
                        m.invoke(obj, params);
                    }
                }
            } catch (Exception e) {
                LOGGER.error("invoke error, e:" + e);
            }
        }
        return obj;
    }

    public static void validate(Object obj) throws Exception{
        Field[] field = obj.getClass().getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            String name = field[i].getName().substring(0,1).toUpperCase() + field[i].getName().substring(1);
            field[i].setAccessible(true);
            if(Objects.equals(field[i].getGenericType().toString(), "class java.lang.String")){
                Method method = obj.getClass().getMethod("get" + name);
                String value = (String) method.invoke(obj);
                if(value == null){
                    throw new ApplicationException(name + "can not be empty");
                }
            }
        }
    }


    public static boolean isJavaClass(Class<?> clz) {
        return clz != null && clz.getClassLoader() == null;
    }
}
